/**
 * Created with IntelliJ IDEA.
 * User: ajhin
 * Date: 4/15/13
 * Time: 11:04 PM
 * To change this template use File | Settings | File Templates.
 */
package societyGames.xmlFragment
{
import flash.events.EventDispatcher;
import flash.utils.describeType;
import flash.utils.getDefinitionByName;

public class XMLFragment extends EventDispatcher
{
  protected var _xmlContainer:XMLContainer;
  protected var _xml:XML;

  public function initialize(xmlContainer:XMLContainer, xml:XML = null):void
  {
    _xmlContainer = xmlContainer;
    if (xml)
    {
      _xml = xml;
    }
    else
    {
      _xml = getDefaultXML();
    }
    initializeChildren();
  }

  private function initializeChildren():void
  {
    var typeXML:XML = describeType(this);
    for each (var variableXML:XML in typeXML.variable)
    {
      tryInitializeChild(variableXML);
    }

    for each (var accessorXML:XML in typeXML.accessor)
    {
      tryInitializeChild(accessorXML);
    }
  }

  private function tryInitializeChild(memberMetadata:XML):void
  {
    tryInitializeChildFragment(memberMetadata);
    tryInitializeChildFragmentCollection(memberMetadata);
  }

  private function tryInitializeChildFragmentCollection(memberMetadata:XML):void
  {
    var fragmentMetadataXMLs:XMLList = memberMetadata.metadata.(@name == "FragmentCollection");
    if (fragmentMetadataXMLs.length() > 0)
    {
      var fragmentMetadataXML:XML = fragmentMetadataXMLs[0];
      var className:String = fragmentMetadataXML.arg.(@key == "className")[0].@value;
      var nodeName:String = fragmentMetadataXML.arg.(@key == "nodeName")[0].@value;
      var type:Class = Class(getDefinitionByName(memberMetadata.@type));
      this[memberMetadata.@name] = type(_xmlContainer.createXMLFragmentCollection(type, _xml, Class(getDefinitionByName(className)), nodeName));
    }
  }

  private function tryInitializeChildFragment(memberMetadata:XML):void
  {
    var fragmentMetadataXMLs:XMLList = memberMetadata.metadata.(@name == "Fragment");
    if (fragmentMetadataXMLs.length() > 0)
    {
      var fragmentMetadataXML:XML = fragmentMetadataXMLs[0];
      var className:String = memberMetadata.@type;
      var nodeName:String = fragmentMetadataXML.arg.(@key == "nodeName")[0].@value;
      var type:Class = Class(getDefinitionByName(className));
      var childFragmentXMLList:XMLList = _xml[nodeName];
      if (childFragmentXMLList.length() == 1)
      {
        this[memberMetadata.@name] = type(_xmlContainer.createChildXMLFragment(type, childFragmentXMLList[0]));
      }
      else if (childFragmentXMLList.length() == 0)
      {
        this[memberMetadata.@name] = null;
      }
      else
      {
        throw new ArgumentError("Malformed XML. Expected 0 or 1 elements: " + nodeName + " in " + _xml);
      }
    }
  }

  public function get xml():XML
  {
    return _xml;
  }

  protected function onInitialize():void
  {
    //Override
  }

  protected function getDefaultXML():XML
  {
    //Override
    throw new Error("Derived classes must override this method.");
    //return null;
  }
}
}
